// SubTreeNode.java
package org.zjx.core.nodes;

import lombok.Getter;
import org.zjx.core.DecisionContext;
import org.zjx.core.DecisionNode;
import org.zjx.core.DecisionStack;
import org.zjx.core.GameAction;

/**
 * 子树节点（用于决策树复用）
 *
 * 这个类实现了一个决策树中的子树节点，允许在决策树中复用另一个决策树结构。
 * 当决策到达此节点时，会将子树节点和返回节点压入调用栈，以便在子树决策完成后能够返回到正确的位置。
 * 如果发生异常，会尝试使用错误处理节点来处理异常情况。
 */
@Getter
public class SubTreeNode implements DecisionNode {
    // 子树节点，表示要执行的决策树
    private final DecisionNode subTree;
    // 返回节点，表示子树执行完成后要返回的节点
    private final DecisionNode returnNode;
    // 错误处理节点，表示在子树执行过程中发生异常时要执行的节点
    private final DecisionNode errorHandler;

    /**
     * 构造函数
     *
     * @param subTree 要执行的子树节点
     * @param returnNode 子树执行完成后要返回的节点
     * @param errorHandler 子树执行过程中发生异常时要执行的节点
     */
    public SubTreeNode(DecisionNode subTree, DecisionNode returnNode, DecisionNode errorHandler) {
        this.subTree = subTree;
        this.returnNode = returnNode;
        this.errorHandler = errorHandler;
    }

    /**
     * 决策方法
     *
     * 在决策过程中，将返回节点和子树节点压入调用栈。
     * 如果发生异常，将错误处理节点压入调用栈。
     *
     * @param context 决策上下文，包含当前状态和调用栈等信息
     * @return 返回的GameAction，通常为null，因为决策逻辑在子树中执行
     */
    @Override
    public GameAction decide(DecisionContext context) {
        try {
            // 将返回节点压入调用栈，保存当前状态快照
            context.getCallStack().push(new DecisionStack.Frame(
                    returnNode,
                    context.getStateAccessor()
            ));
            // 将子树节点压入调用栈，开始执行子树决策
            context.getCallStack().push(new DecisionStack.Frame(
                    subTree,
                    context.getStateAccessor()
            ));
        } catch (Exception e) {
            // 如果发生异常，尝试使用错误处理节点
            if (errorHandler != null) {
                context.getCallStack().push(new DecisionStack.Frame(
                        errorHandler,
                        context.getStateAccessor()
                ));
            }
            // 抛出异常，由上层处理
            throw e;
        }
        // 返回null，因为决策逻辑在子树中执行
        return null;
    }
}